package com.wangzhen.spring.ioc.dependcy.loopup;

import com.wangzhen.spring.ioc.dependcy.entity.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 通过ObjectProvider来实现延迟加载（针对非Lazy bean）
 * 1、ObjectProvider继承自ObjectFactory
 * 2、当调用ObjectFactory#getObject方法的时候，才会获取到实际对象 （如果context中不存在此bean会抛出异常）
 * 3、通过ObjectProvider#getIfAvailable方法可以实现一个兜底方案，如果context中没有相应的bean，可以自己实例化一个
 *      context中不存此bean，也不会抛出异常！！
 * 4、ObjectProvider 既可以获取单一类型bean，也可以获取集合类型bean
 *
 */
public class ObjectProviderDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(ObjectProviderDemo.class);

        applicationContext.refresh();
        // 通过ObjectProvider方式获取bean对象
        lookUpByObjectProvider(applicationContext);
        //
        lookUpByIfAvailble(applicationContext);
        // 输出打印ObjectProvider
        lookUpByStream(applicationContext);

        applicationContext.close();
    }

    @Bean
    @Primary
    public String helloWorld() {
        return "hello world";
    }

    @Bean
    public String message() {
        return "message";
    }

    /**
     *
     * @param beanFactory
     */
    public static void lookUpByStream(BeanFactory beanFactory) {
        System.out.println("----------------ObjectProvider print -------------------");
        ObjectProvider<String> beanProvider = beanFactory.getBeanProvider(String.class);
        // 方式一： ObjectProvider实现了Iterable接口，因此可以将String类型的所有bean实例直接打印
        /*for (String s : beanProvider) {
            System.out.println(s);
        }*/
        // 方式二：直接利用stream来打印
        beanProvider.stream().forEach(System.out::println);
        // 方式一和方式二是等价的
    }

    /**
     * 通过jdk8 的方式来实现一个兜底，如果访问的bean不存在的时候，可以创建一个默认bean
     * @param beanFactory
     */
    public static void lookUpByIfAvailble(BeanFactory beanFactory) {
        // 在该上下文中并没有注册user这个bean
        ObjectProvider<User> beanProvider = beanFactory.getBeanProvider(User.class);
        // user 和user1 的结果一样
        User user = beanProvider.getIfAvailable(() -> new User());
        User user1 = beanProvider.getIfAvailable(User::createUser);
        System.out.println(user);
    }

    /**
     * 非延迟bean，通过ObjectProvide来达到延迟访问的效果
     * @param beanFactory
     */
    public static void lookUpByObjectProvider(BeanFactory beanFactory) {
        ObjectProvider<String> bean = beanFactory.getBeanProvider(String.class);
        System.out.println(bean.getObject());
    }

}
